#include "wx_pch.h"

#include <wx/wfstream.h>
#include <wx/datstrm.h>
//#include <wx/file.h>
#include <wx/image.h>
#include <wx/string.h>
#include <wx/stopwatch.h>

#include "wxTraverser.h"

/*
    Movie Header Atom
*/
struct MVHD
{
    wxUint32 Size; // Size of the comlete mvhd atom in bytes
    wxByte Type[4]; // 4 byte = 'mvhd'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00] ???
    wxUint32 CreationTime; // Seconds since 00:00 1.1.1904
    wxUint32 ModificationTime; // Seconds since 00:00 1.1.1904
    wxUint32 TimeScale; // Internal time coordinate system of this movie. 60 means 60 ticks per second
    wxUint32 Duration; // length of the longest track in ticks (TimeScale)
    wxByte PreferredRate[4]; // 4 byte float, playback speed set this to 1.0 [00 01 00 00]
    wxByte PreferredVolume[2]; // 2 byte float, maximum is 1.0 we set this to [00 FF]
    wxByte Reserved[10]; // 10 bytes used internal, set to [00 00 00 00 00 00 00 00 00 00]
    wxByte TransformationMatrix[36]; // 3x3 matrix with 4 byte float values (4*9=36 bytes), used to transform the data
    wxUint32 PreviewTime; // Time position for a preview in ticks, we can set this to 0
    wxUint32 PreviewDuration; // Length of the preview in ticks, we can set this to 0
    wxUint32 PosterTime; // Time position for the poster in ticks, we can set this to 0
    wxUint32 SelectionTime; // Start time for the selection in ticks, we can set this to 0
    wxUint32 SelectionDuration; // Legth time for the selection in ticks, we can set this to 0
    wxUint32 CurrentTime; // Time position for the current position in the movie in ticks, we can set this to 0
    wxUint32 NextTrackID; // A new track that is added to the file will get this ID. We always have 3 tracks with id(1, 2, 3) so next track got ID 4 [00 00 00 04]
};

/*
    Track Header Atom
*/
struct TKHD
{
    wxUint32 Size; // size of the complete tkhd atom in bytes
    wxByte Type[4]; // 4 byte = 'tkhd'
    wxByte Version; // set to [00]
    /*
    Track enabled
    Indicates that the track is enabled. Flag value is 0x0001.
    Track in movie
    Indicates that the track is used in the movie. Flag value is 0x0002.
    Track in preview
    Indicates that the track is used in the movies preview. Flag value is 0x0004.
    Track in poster
    Indicates that the track is used in the movies poster. Flag value is 0x0008.
    */
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 0F] ???
    wxUint32 CreationTime; // Seconds since 00:00 1.1.1904
    wxUint32 ModificationTime; // Seconds since 00:00 1.1.1904
    wxUint32 TrackID; // unique identifier for this track
    wxByte Reserved1[4]; // 4 byte for internal use, set to 0 [00 00 00 00]
    wxUint32 Duration; // length of the track in ticks (TimeScale)
    wxByte Reserved2[8]; // 8 byte for internal use, set to 0 [00 00]
    wxUint16 Layer; // z-index of this track, when overlaying, set this to 0 cause we dont use overlay [00 00]
    wxUint16 AlternateGroup; // Group specification of this track for use of i.e. different quality, languages, ..., we don't need it and can set this to 0 [00 00]
    wxByte Volume[2]; // 2 byte float sound volume of this track normal value is 1.0, we can set this to [00 00]
    wxByte Reserved3[2]; // 2 byte for internal use, set to 0 [00 00]
    wxByte TransformationMatrix[36]; // 3x3 matrix with 4 byte float values (4*9=36 bytes), used to transform the data
    wxByte *TrackWidth; // 4 byte float the width in pixel for this track (first 2 bytes are big endian wxUint16)
    wxByte *TrackHeight; // 4 byte float the height in pixel for this track (first 2 bytes are big endian wxUint16)
};

/*
    Edit List Atom
*/
struct ELST
{
    wxUint32 Size; // size of the complete elst atom in bytes
    wxByte Type[4]; // 4 byte = 'elst'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00]
    wxUint32 EntryCount; // 4 byte integer presenting the number of rows in the following edit list table, we only have one row that contains the information for the whole track [00 00 00 01]
    // edit list table, we only have one entry
    //{
        wxUint32 Duration;
        wxUint32 StartTime;
        wxByte PlaybackRate[4];
    //}
};

/*
    Track Edit Atom
*/
struct EDTS
{
    wxUint32 Size; // size of the complete edts atom in bytes
    wxByte Type[4]; // 4 byte = 'edts'
    ELST EditList; //
};

/*
    Track Reference Atom
*/
struct TREF
{
    wxUint32 Size; // size of the complete tref atom in bytes
    wxByte Type[4]; // 4 byte = 'tref'
    // reference table, we only have a single entry
    //{
        wxUint32 ReferenceSize; // size of the complete atom in bytes
        wxByte ReferenceType[4]; // 4 byte = 'obje' || 'imgt'
        wxUint32 ReferenceTrackID; // 4 byte integer containing ID of the reference track, this is an array but we only need one entry
    //}
};

/*
    Media Header Atom
*/
struct MDHD
{
    wxUint32 Size; // size of the complete mdhd atom in bytes
    wxByte Type[4]; // 4 byte = 'mdhd'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00]
    wxUint32 CreationTime; // Seconds since 00:00 1.1.1904
    wxUint32 ModificationTime; // Seconds since 00:00 1.1.1904
    wxUint32 TimeScale; // 4 byte integer the amount of time ticks per second when playback this track
    wxUint32 Duration;  // length of the media in ticks (TimeScale)
    wxUint16 LanguageCode; // 2 byte integer
    wxUint16 PlaybackQuality; //
};

/*
    Handler Reference Atom
*/
struct HDLR
{
    wxUint32 Size; // size of the complete hdlr atom in bytes
    wxByte Type[4]; // 4 byte = 'hdlr'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00]
    wxByte ComponentType[4]; // 4 byte = '????'
    wxByte ComponentSubType[4]; // 4 byte = '????'
    wxByte Reserved[12]; // 12 bytes for internal use (component manufacturer, flags, flags mask)
    wxByte ComponentNameLength; // 1 byte character count of component name
    wxByte* ComponentName; //
};

/*
    Base Media Information Atom
*/
struct GMIN
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte = 'gmin'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00]
    wxUint16 GraphicMode;
    wxByte OpColor[6]; // 6 byte default [80 00 80 00 80 00]
    wxUint16 Balance; // 2 byte balance between speakers left/right
    wxByte Reserved[2]; // 2 bytes for internal use [00 00]
};

/*
    Base Media Information Header Atom
*/
struct GMHD
{
    wxUint32 Size; // size of the complete gmhd atom in bytes
    wxByte Type[4]; // 4 byte = 'gmhd'
    GMIN BaseInformation;
};

/*
    Video Media Information Header Atom
*/
struct VMHD
{
    wxUint32 Size; // size of the complete vmhd atom in bytes
    wxByte Type[4]; // 4 byte = 'vmhd'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags should be set to [00 00 01]
    wxUint16 GraphicMode;
    wxByte OpColor[6]; // 6 byte default [80 00 80 00 80 00]
};

/*
    Data Reference Atom
*/
struct DREF
{
    wxUint32 Size; // size of the complete dref atom in bytes
    wxByte Type[4]; // 4 byte = 'dref'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00]
    wxUint32 EntryCount; // 4 byte integer, we have one entry
    // table with only one entry
    //{
        wxUint32 EntrySize; // size of the complete atom in bytes
        wxByte EntryType[4]; // 4 byte = 'alis'
        wxByte EntryVersion; // This value can be set to 0
        wxByte EntryFlags[3]; // 3 byte integer describing some flags should be set to [00 00 01]
    //}
};

/*
    Data Information Atom
*/
struct DINF
{
    wxUint32 Size; // size of the complete dinf atom in bytes
    wxByte Type[4]; // 4 byte = 'dinf'
    DREF DataReference;
};

/*
    The VR world header atom is a leaf atom. Its atom type is kQTVRWorldHeaderAtomType ('vrsc').
    It contains the name of the scene and the default node ID to be used when the file is first
    opened aswell as fields reserved for future use.
*/
struct VRSC
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte if this is the root -> 'vrsc'
    wxUint16 MajorVersion; // The major version number of the file format.
    wxUint16 MinorVersion; // The minor version number of the file format.
    wxUint32 NameAtomID; // The ID of the string atom that contains the name of the scene. That atom should be a sibling of the VR world header atom. The value of this field is 0 if no name string atom exists.
    wxUint32 DefaultNodeID; // The ID of the default node (that is, the node to be displayed when the file is first opened)
    wxByte UNKNOWN[12]; // 12 byte
    wxByte VRWorldFlags[4]; // 4 byte unused, can be set to [00 00 00 00]
    wxByte Reserved[8]; // 8 Bytes for intrnal use, can be set to [00 00 00 00 00 00 00 00]
};

/*
    The imaging parent atom is the parent atom of one or more node-specific imaging atoms.
    Its atom type is kQTVRImagingParentAtomType ('imgp'). Only panoramas have an imaging atom defined.
*/
struct IMGP
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte 'imgp'
    wxUint16 MajorVersion;
    wxUint16 MinorVersion;
    wxByte Reserved1[2];
    wxUint16 ChildCount;
    wxByte Reserved2[4];
    // Child Atoms
    //{

    //}
};

/*

*/
struct NLOC
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte 'nloc'
    wxUint16 MajorVersion;
    wxUint16 MinorVersion;
    wxByte Reserved1[2];
    wxUint16 ChildCount;
    wxByte Reserved2[4];
    wxUint16 UNKNOWN_1; //
    wxUint16 UNKNOWN_2; //
    wxByte NodeType[4]; // 4 byte node type 'obje'
    wxByte UNKNOWN_3[16]; // 16 byte location flags, location data, reserved [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
};

/*

*/
struct VRNI
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte 'vrni'
    wxUint16 MajorVersion;
    wxUint16 MinorVersion;
    wxByte Reserved1[2];
    wxUint16 ChildCount;
    wxByte Reserved2[4];
    // Child Atoms
    //{
        NLOC NodeLocationAtom;
    //}
};

/*

*/
struct VRNP
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte 'vrnp'
    wxUint16 MajorVersion;
    wxUint16 MinorVersion;
    wxByte Reserved1[2];
    wxUint16 ChildCount;
    wxByte Reserved2[4]; // 4 byte [00 00 00 00]
    // Child Atoms
    //{
        VRNI NodeIDAtom;
    //}
};

/*
    A node header atom is a leaf atom that describes the type and ID of a node,
    as well as other information about the node
*/
struct NDHD
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte 'ndhd'
    wxUint16 MajorVersion;
    wxUint16 MinorVersion;
    wxByte Reserved1[2];
    wxUint16 ChildCount;
    wxByte Reserved2[4];
    wxUint16 UNKNOWN_1; //
    wxUint16 UNKNOWN_2; //
    wxByte NodeType[4]; // 4 byte node type 'obje'
    wxByte UNKNOWN_3[20]; // 16 byte location flags + location data + reserved [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
};

/*
    QTVRObjectSampleAtom
*/
struct OBJI
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte 'obji'
    wxUint16 majorVersion; // kQTVRMajorVersion
    wxUint16 minorVersion; // kQTVRMinorVersion
    wxByte UNKNOWN[12]; // [00 00 00 00 00 00 00 00 00 02 00 00]
    wxUint16 movieType; // ObjectUITypes
    wxUint16 viewStateCount; // The number of view states 1 based
    wxUint16 defaultViewState; // The default view state number. The number must be 1 to viewStateCount
    wxUint16 mouseDownViewState; // The mouse down view state.   The number must be 1 to viewStateCount
    wxUint32 viewDuration; // The duration of each view including all animation frames in a view
    wxUint32 columns;                // Number of columns in movie
    wxUint32 rows;                   // Number rows in movie
    wxByte mouseMotionScale[4];       // 180.0 for kStandardObject or kQTVRObjectInScene, actual degrees for kOldNavigableMovieScene.
    wxByte minPan[4];                 // Start   horizontal pan angle in degrees
    wxByte maxPan[4];                 // End     horizontal pan angle in degrees
    wxByte defaultPan[4];             // Initial horizontal pan angle in degrees (poster view)
    wxByte minTilt[4];                // Start   vertical   pan angle in degrees
    wxByte maxTilt[4];                // End     vertical   pan angle in degrees
    wxByte defaultTilt[4];            // Initial vertical   pan angle in degrees (poster view)
    wxByte minFieldOfView[4];         // minimum field of view setting (appears as the maximum zoom effect) must be >= 1
    wxByte fieldOfView[4];            // the field of view range must be >= 1
    wxByte defaultFieldOfView[4];     // must be in minFieldOfView and maxFieldOfView range inclusive
    wxByte defaultViewCenterH[4];
    wxByte defaultViewCenterV[4];
    wxByte viewRate[4];
    wxByte frameRate[4];
    wxUint32 animationSettings;      //32 reserved bit fields
    wxUint32 controlSettings;        //32 reserved bit fields
};

/*
    QT (root) Atom Header
*/
struct SEAN
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte if this is the root -> 'sean'
    wxUint32 AtomID; // 4 byte integer
    wxByte Reserved1[2]; // 2 Bytes for intrnal use, can be set to 0
    wxUint16 ChildCount; // 2 byte integer the amount of child atoms
    wxByte Reserved2[4]; // 4 Bytes for intrnal use, can be set to 0
    // Array with child atoms, we have exactly 3 children
    //{
        VRSC WorldHeaderAtom;
        IMGP ImagingParentAtom;
        VRNP NodeParentAtom;
        NDHD NodeHeaderAtom;
        OBJI ObjectInfoAtom;
    //}
};

/*
    QT Atom Container Header
*/
struct QTACH
{
    wxByte Reserved[10]; // 10 Bytes for intrnal use, can be set to 0
    wxUint16 LockCount; // 2 byte integer describing
    SEAN AtomHeader;
};

/*
    Sample Description Table Entry
*/
struct SDQTVR
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte = 'qtvr'
    wxByte Reserved[6]; // 6 bytes ??? for intrnal use, can be set to 0
    wxUint16 DataReferenceIndex; // 2 byte integer describing
    QTACH ContainerAtomHeader; //
};

/*
    Sample Description Table Entry
*/
struct SDBLANK
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte = ''
    wxByte Reserved[6]; // 6 Bytes for intrnal use, can be set to 0
    wxUint16 DataReferenceIndex; // 2 byte integer describing
};

/*
    Sample Description Table Entry
*/
struct SDJPG
{
    wxUint32 Size; // size of the complete atom in bytes
    wxByte Type[4]; // 4 byte = 'jpeg'
    wxUint16 Version; // This value can be set to 0
    wxUint16 RevisionLevel;
    wxByte Reserved[8]; // 8 Bytes [00 00 00 01 00 01 00 01]
    wxByte Vendor[4]; // 4 Bytes = 'appl'
    wxUint32 TemporalQuality;
    wxUint32 SpatialQuality;
    wxUint16 Width;
    wxUint16 Height;
    wxByte HorizontalResolution[4]; // 4 byte float dpi
    wxByte VerticalResolution[4]; // 4 byte float dpi
    wxUint32 DataSize;
    wxUint16 FrameCount;
    wxByte CompressorName[32]; // 32 byte pascal string "Photo - JPEG"
    wxUint16 ColorDepth;
    wxUint16 ColorTableID;
};

/*
    Sample Table Description Atom
*/
struct STSD
{
    wxUint32 Size; // size of the complete stsd atom in bytes
    wxByte Type[4]; // 4 byte = 'stsd'
    wxByte Version; // This value can be set to 0
    wxByte Flags[3]; // 3 byte integer describing some flags can be set to [00 00 00]
    wxUint32 EntryCount; // 4 byte integer, we have one entry
    // Array of sample description atoms, but we always have only one entry that is type of 'qtvr', '' or 'jpeg'
    //{
        SDQTVR QtvrSampleDescription;
        SDBLANK EmptySampleDescription;
        SDJPG JpegSampleDescription;
    //}

};

/*
    Sample Table Time-to-Sample Atom
*/
struct STTS
{
    wxUint32 Size; // size of the complete stts atom in bytes
    wxByte Type[4]; // 4 byte = 'stts'
    wxByte Version; // 1 byte [00]
    wxByte Flags[3]; // 3 byte [00 00 00]
    wxUint32 EntryCount; // number of entries in the sample table
    // sample time table, we only have a single entry
    //{
        wxUint32 SampleCount; // number of samples in a chunk
        wxUint32 SampleDuration; // duration of a single sample in ticks
    //}
};

/*
    Sample Table Sample-to-Chunk Atom
*/
struct STSC
{
    wxUint32 Size; // size of the complete stsc atom in bytes
    wxByte Type[4]; // 4 byte = 'stsc'
    wxByte Version; // 1 byte [00]
    wxByte Flags[3]; // 3 byte [00 00 00]
    wxUint32 EntryCount; // number of entries in the chunk table
    // sample chunk table, we only have a single entry
    //{
        wxUint32 FirstChunk;
        wxUint32 ChunkSampleCount;
        wxUint32 SampleDescriptionID;
    //}
};

/*
    Sample Table Size Atom
*/
struct STSZ
{
    wxUint32 Size; // size of the complete stsz atom in bytes
    wxByte Type[4]; // 4 byte = 'stsz'
    wxByte Version; // 1 byte [00]
    wxByte Flags[3]; // 3 byte [00 00 00]
    wxUint32 SampleSize; // 4 byte size of the mdat atom (the following table will not be used if this value is > 0)
    wxUint32 EntryCount; // number of entries in the size table
    wxUint32 *SampleSizeTable; // each entry contains the size of the sample data in byte
};

/*
    Sample Table Chunk-Offset Atom
*/
struct STCO
{
    wxUint32 Size; // size of the complete stco atom in bytes
    wxByte Type[4]; // 4 byte = 'stco'
    wxByte Version; // 1 byte [00]
    wxByte Flags[3]; // 3 byte [00 00 00]
    wxUint32 EntryCount; // number of entries in the offset table
    wxUint32 *ChunkOffsetTable; // each entry contains the (file) offset of the chunk data in byte
};

/*
    Sample Table Atom
*/
struct STBL
{
    wxUint32 Size; // size of the complete stbl atom in bytes
    wxByte Type[4]; // 4 byte = 'stbl'
    STSD TableDescription;
    STTS TableTimeToSample;
    STSC TableSampleToChunk;
    STSZ TableChunkSize;
    STCO TableChunkOffset;
};

/*
    Media Information Atom
*/
struct MINF
{
    wxUint32 Size; // size of the complete minf atom in bytes
    wxByte Type[4]; // 4 byte = 'minf'
    GMHD BaseMediaHeader;
    VMHD VideoMediaHeader;
    HDLR HandleReference;
    DINF DataInformation;
    STBL SampleTable;
};

/*
    Media Atom
*/
struct MDIA
{
    wxUint32 Size; // size of the complete mdia atom in bytes
    wxByte Type[4]; // 4 byte = 'mdia'
    MDHD MediaHeader;
    HDLR HandlerReference;
    MINF MediaInformation;
};

/*
    Track
*/
struct TRAK
{
    wxUint32 Size; // size of the complete trak atom in bytes
    wxByte Type[4]; // 4 Bytes = 'trak'
    TKHD TrackHeader;
    EDTS TrackEdit;
    TREF TrackReference;
    MDIA TrackMedia;
};


/*
    Controller Type
*/
struct CTYP
{
    wxUint32 Size; // size of the complete ctyp atom in bytes
    wxByte Type[4]; // 4 Bytes = 'ctyp'
    wxByte Data[4]; // 4 bytes = 'qtvr'
};

/*
    User Data
*/
struct UDTA
{
    wxUint32 Size; // size of the complete udta atom in bytes
    wxByte Type[4]; // 4 Bytes = 'udta'
    CTYP ControllerType;
};

/*
    Movie Atom
*/
struct MOOV
{
    wxUint32 Size; // size of the complete moov atom in bytes
    wxByte Type[4]; // 4 Bytes = 'moov'
    MVHD MovieHeader;
    TRAK QTVRTrack;
    TRAK ObjectTrack;
    TRAK ObjectImageTrack;
    UDTA UserData;
};

/*
    Movie Data Atom
*/
struct MDAT
{
    wxUint32 Size; // size of the complete moov atom in bytes
    wxByte Type[4]; // 4 Bytes = 'mdat'
    wxByte Seperator[12];
    SEAN NodeHeaderRootAtom; // ndhd -> obje
    SEAN ObjectInformationRootAtom; // obji
    wxUint32 ImageCount;
};

class QT
{
    /*
        Default Constructor
        We don't use it
    */
    public: QT();
    /*
        Advanced Constructur
        Creates an whole quicktime vr object structure based on the images
    */
    public: QT(wxImage images[], wxUint32 imgCount, wxUint32 panCount, wxUint32 tiltCount);
    /*
        Destructor
        Destroy all members
    */
    public: ~QT();

    /*
        Members
    */
    MOOV moov;
    MDAT mdat;

    /*
        Functions
    */
    void save(wxString FilePath);
};
